package com.mspbots.cw.amqp.receivers;

import com.fasterxml.jackson.databind.JsonNode;
import com.mspbots.cw.amqp.BaseReceiver;
import com.mspbots.cw.amqp.CallbackAction;
import com.mspbots.cw.amqp.model.ExceptionLog;
import com.mspbots.cw.amqp.model.TenantSchedule;
import lombok.extern.log4j.Log4j2;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.data.r2dbc.query.Criteria;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Optional;

/**
 * com.mspbots.core.amqp.receivers.SchedulesReceiver
 *
 * @author Alex bob(https://github.com/vnobo)
 * @date Created by 2019/10/11
 */
@Log4j2
@Component
public class SchedulesReceiver extends BaseReceiver {

    @RabbitListener(queues = "core.schedules")
    public void processMessage(JsonNode scheduleNode) {
        try{
            if (scheduleNode.get("id").asInt() == 0) {
                log.error("Receiver core.schedules tenant:{},entry:{}", scheduleNode.get("tenantId").asInt(),
                        scheduleNode);
                return;
            }

            log.debug("Receiver core.schedules tenant {},entry {}", scheduleNode.get("tenantId").asInt(),
                    scheduleNode.get("id").asLong());

            if (!ObjectUtils.isEmpty(scheduleNode.get("action")) && scheduleNode.get("action").asText().equals(CallbackAction.deleted.name())) {
                this.databaseClient.delete().from(TenantSchedule.class)
                        .matching(Criteria.where("tenantId").is(scheduleNode.get("tenantId").asInt())
                                .and("cwId").is(scheduleNode.get("id").asLong()))
                        .fetch().rowsUpdated().block(Duration.ofSeconds(10));
            }

            TenantSchedule schedule = TenantSchedule.builder()
                    .tenantId(scheduleNode.get("tenantId").asInt())
                    .cwId(scheduleNode.get("id").asLong())
                    .objectId(!ObjectUtils.isEmpty(scheduleNode.get("objectId")) ? scheduleNode.get("objectId").asLong() : 0)
                    .createdTime(ObjectUtils.isEmpty(scheduleNode.findValue("dateEntered")) ? null :
                            LocalDateTime.parse(scheduleNode.findValue("dateEntered").asText(),
                                    DateTimeFormatter.ISO_ZONED_DATE_TIME))
                    .updatedTime(ObjectUtils.isEmpty(scheduleNode.findValue("lastUpdated")) ? null :
                            LocalDateTime.parse(scheduleNode.findValue("lastUpdated").asText(),
                                    DateTimeFormatter.ISO_ZONED_DATE_TIME))
                    .doneFlag(!ObjectUtils.isEmpty(scheduleNode.get("doneFlag")) ? scheduleNode.get("doneFlag").asBoolean() : null)
                    .syncTime(LocalDateTime.now())
                    .name(!ObjectUtils.isEmpty(scheduleNode.get("name")) ? scheduleNode.get("name").asText() : null)
                    .dateStart(!StringUtils.isEmpty(scheduleNode.get("dateStart")) ?
                            LocalDateTime.parse(scheduleNode.get("dateStart").asText(), DateTimeFormatter.ISO_DATE_TIME) : null)
                    .dateEnd(!StringUtils.isEmpty(scheduleNode.get("dateEnd")) ?
                            LocalDateTime.parse(scheduleNode.get("dateEnd").asText(), DateTimeFormatter.ISO_DATE_TIME) : null)
                    .extend(scheduleNode).build();

            JsonNode memberNode = scheduleNode.get("member");
            if (!ObjectUtils.isEmpty(memberNode)) {
                schedule.setIdentifier(memberNode.get("identifier").asText());
                schedule.setMemberId(memberNode.get("id").asInt());
            }

            Optional<Long> optionalLong = this.databaseClient.execute("select id from tenant_schedule " +
                    "where tenant_id =:tenantId and cw_id =:cwId")
                    .as(Long.class)
                    .bind("tenantId", schedule.getTenantId())
                    .bind("cwId", schedule.getCwId())
                    .fetch()
                    .one().blockOptional();
            if (optionalLong.isPresent() && optionalLong.get() > 0) {
                log.debug("Receiver schedules tenant id:{},cw id:{}, update id:{}",
                        schedule.getTenantId(), schedule.getCwId(), optionalLong.get());
                schedule.setId(optionalLong.get());
                schedule.setSyncTime(LocalDateTime.now());
                this.databaseClient.update().table(TenantSchedule.class).using(schedule)
                        .fetch().rowsUpdated().block();
            } else {
                this.databaseClient.insert().into(TenantSchedule.class).using(schedule)
                        .fetch().rowsUpdated().block();
            }
        }catch (Exception e){
            if (!ObjectUtils.isEmpty(scheduleNode.get("tenantId"))){
                this.databaseClient.insert().into(ExceptionLog.class).using(
                        ExceptionLog.builder()
                                .tenantId(scheduleNode.get("tenantId").asInt())
                                .name("core.schedules")
                                .status(500)
                                .type("core.schedules")
                                .msg(e.getMessage()+","+scheduleNode.toString() )
                                .build()
                ).fetch().rowsUpdated().block(Duration.ofSeconds(10));
            }
        }
    }
}
